const fs = require("fs")
const path = require("path")
const os = require("os");
const {execSync} = require("child_process");
const fse = require("fs-extra");
module.exports = handleVueTemplate

function handleVueTemplate(basePath, viewAnswer, isAll, pluginType) {
  handleAppVue(basePath, viewAnswer)
  handleComponentsIndexjs(basePath, viewAnswer)
  handleComponentDevelopmentAppVue(basePath, viewAnswer)
  handleComponentDevelopmentMockDatajs(basePath, viewAnswer)
  handleUtilHandlePlatformAdapterjs(basePath,viewAnswer)
  generateNewFiles(basePath, viewAnswer)
  deleteExtraFiles(basePath, viewAnswer)
  basePath = moveFiles(basePath, isAll, pluginType)
  return basePath
}

function moveFiles(basePath, isAll, pluginType) {
  let pathPrefix
  //通过本项目启动
  if (process.env["sdataPlugins"] === "true") {
    pathPrefix = path.resolve(__dirname, `../packages`)
  } else {
    pathPrefix = process.cwd()
  }
  if (isAll) {
    mkdirSync(path.resolve(pathPrefix, `${pluginType}/${basePath}`))
    fse.copySync(path.resolve(__dirname, `./${basePath}`), path.resolve(pathPrefix, `${pluginType}/${basePath}`))
    mkdirSync(path.resolve(pathPrefix, `${pluginType}/src/utils/handlePlatform`))
    fse.copySync(path.resolve(__dirname, `./${basePath}/src/utils/handlePlatform/adapter.js`), path.resolve(pathPrefix, `${pluginType}/src/utils/handlePlatform/adapter.js`))
    mkdirSync(path.resolve(pathPrefix, `${pluginType}/src/components/development`))
    fse.copySync(path.resolve(__dirname, `./${basePath}/src/components/development/mockData.js`), path.resolve(pathPrefix, `${pluginType}/src/components/development/mockData.js`))
    fse.removeSync(path.resolve(__dirname, `./${basePath}`))
    basePath = path.resolve(pathPrefix, `${pluginType}`)
    return basePath
  } else {
    mkdirSync(path.resolve(pathPrefix, basePath))
    fse.copySync(path.resolve(__dirname, `./${basePath}`), path.resolve(pathPrefix, basePath))
    fse.removeSync(path.resolve(__dirname, `./${basePath}`))
    basePath = path.resolve(pathPrefix, basePath)
    let batchFlag = process.argv.slice(2)[0] == "--batch"
    !batchFlag && openFiles(basePath)
  }
}


function openFiles(basePath) {
  let startCommond = os.type() === "Darwin" ? "open" : "start"
  try {
    execSync(`${startCommond} ${basePath}`)
    execSync(`${startCommond} ${basePath}/src/utils/handlePlatform/adapter.js`)
    execSync(`${startCommond} ${basePath}/src/components/development/mockData.js`)
  } catch (e) {
    console.log("自动打开文件失败，请手动打开，目录名：src/utils/handlePlatform/adapter.js")
    console.log("自动打开文件失败，请手动打开，目录名：src/components/development/mockData.js")
  }
}

function handleUtilHandlePlatformAdapterjs(basePath, viewAnswer) {
  const needProcess = viewAnswer.some((item) => {
    return item.process == true
  })
  const templateContent = `export default function adapter(props) {
  const onlineDevelopmentMode = process.env.VUE_APP_ONLINE_DEVELOPMENT_MODE === "true" || process.env.REACT_APP_ONLINE_DEVELOPMENT_MODE === "true"
  if (process.env.NODE_ENV === "production" || (onlineDevelopmentMode && !window.online_development_islocal)) {
    /**
     *@example
     * props.type = (props.type === "designConfiguration" ? "designConfiguration" : "main")
     *   props.changeConfiguration && (props.changeCustomConfig = props.changeConfiguration)
     *   if (props.type === "designConfiguration") {
     *     props.customConfig = JSON.parse(props.configuration)
     *   } else {
     *     props.customConfig = props.configuration
     *   }
     *
     */
     ${needProcess
    ? "/**\n     * 封装smardaten触发事件的方法\n     * @param {String} eventName 事件名\n     * @param {Object} payload 事件传参\n     * @example\n     * triggerEvent(\"click\",{value:\"123\"})\n     *\n     */\n    /*props.triggerEvent = function (eventName, payload = {}) {\n     props.componentId && window.eventCenter?.triggerEvent(\n     props.componentId,\n     eventName,\n     //payload需为一个object\n     payload\n     )\n     }*/"
    : ""}
    // return props
  }
  return props
}
`
  fs.writeFileSync(path.resolve(__dirname, `./${basePath}/src/utils/handlePlatform/adapter.js`), templateContent)
}

// generateNewFiles("", [
//   {viewType: "main", process: false},
//   {viewType: "designConfiguration", process: false},
//   {viewType: "data", process: true}
// ])
function handleComponentDevelopmentMockDatajs(basePath, viewAnswer) {
  const hasDesignConfiguration = viewAnswer.some((item) => {
    return item.viewType == "designConfiguration"
  })
  const templateContent = `import getPluginType from "../../utils/handlePlatform/getPluginType.js"
  
const pluginType = getPluginType()
${hasDesignConfiguration
    ? "const configJson = require('../../../pluginTemp/config.json');\nconst configJsonId = configJson.id\nlet customConfig = JSON.parse(localStorage.getItem(`${pluginType}-secondary-${configJsonId}`))?.customConfig || {}\nexport let mockCustomConfig = customConfig\nexport const mockChangeCustomConfig = (customConfig) => {\n  const mockData = JSON.parse(localStorage.getItem(`${pluginType}-secondary-${configJsonId}`)) || {}\n  mockData.customConfig = JSON.parse(customConfig)\n  localStorage.setItem(`${pluginType}-secondary-${configJsonId}`, JSON.stringify(mockData))\n}"
    : ""}
export default {

}
  `
  // console.log(templateContent);
  fs.writeFileSync(path.resolve(__dirname, `./${basePath}/src/components/development/mockData.js`), templateContent)
}

function handleComponentDevelopmentAppVue(basePath, viewAnswer) {
  const hasDesignConfiguration = viewAnswer.some((item) => {
    return item.viewType == "designConfiguration"
  })
  let importStatement = viewAnswer.map((item) => {
    let componentName = `${item.viewType.slice(0, 1).toUpperCase()}${item.viewType.slice(1)}`
    return `${componentName}`
  }).join(",\n    ")
  let templateContent = `<script>
import {
  ${importStatement}
} from "../index.js"${hasDesignConfiguration
    ? "\nimport mockData, {\n  mockCustomConfig,\n  mockChangeCustomConfig\n} from \"./mockData.js\""
    : "\nimport mockData from \"./mockData.js\""}
import Utils from "@/utils"

export default {
  name: "Development",
  components: {
    ${importStatement}
  },
  data() {
  return {
    renderMap: [
      ${viewAnswer.filter((item) => item.viewType != "designConfiguration").map((item) => {
    let componentName = `${item.viewType.slice(0, 1).toUpperCase()}${item.viewType.slice(1)}`
    return `{ type: "${componentName}", component: ${componentName} }`
  }).join(",\n      ")}
    ],${hasDesignConfiguration ? "\n    mainKey: Utils.generateUUID()," : ""}
    vueProps: {${hasDesignConfiguration ? "\n      customConfig: mockCustomConfig,\n      changeCustomConfig: this.changeCustomConfig," : ""}
      ...mockData  
    }
  }
},
  methods: {
  ${hasDesignConfiguration ? "toggleShrink() {\n" +
                             "      let sideClose = this.$refs.side.style.display == \"none\" ? true : false\n" +
                             "      this.$refs.side.style.display = sideClose ? \"block\" : \"none\"\n" +
                             "      this.$refs.carousel.style.width = sideClose ? \"calc(100% - 300px)\" : \"100%\"\n" +
                             "      this.$refs.toggle.style.transform = sideClose ? \"translate(-20px,-8px)\" : \"translate(-20px,-8px) rotateY(180deg)\"\n" +
                             "    },\n" +
                             "    handleAarouselStyle() {\n" +
                             "      let sideClose = this.$refs.side.style.display == \"none\" ? true : false\n" +
                             "      this.$refs.side.style.display = sideClose ? \"none\" : \"block\"\n" +
                             "      this.$refs.carousel.style.width = sideClose ? \"100%\" : \"calc(100% - 300px)\"\n" +
                             "      this.$refs.toggle.style.transform = sideClose ? \"translate(-20px,-8px) rotateY(180deg)\" : \"translate(-20px,-8px)\"\n" +
                             "    },\n" +
                             "    changeCustomConfig(customConfig) {\n" +
                             "      this.vueProps.customConfig = JSON.parse(customConfig)\n" +
                             "      this.mainKey = Utils.generateUUID()\n" +
                             "      this.$nextTick(() => {\n" +
                             "        this.handleAarouselStyle()\n" +
                             "      })\n" +
                             "      mockChangeCustomConfig(customConfig)\n" +
                             "    }" : ""}
  },
  render(h) {
    return (
      <div id="development">
        <div id="main" ref="carousel" style={{position: "relative"}} ${hasDesignConfiguration ? "key={this.mainKey}" : ""}>
          ${hasDesignConfiguration ? "<el-button\n" +
                                     "            style={{\n" +
                                     "              width: \"40px\",\n" +
                                     "              height: \"40px\",\n" +
                                     "              position: \"absolute\",\n" +
                                     "              zIndex: \"2000\",\n" +
                                     "              top: \"50%\",\n" +
                                     "              right: 0,\n" +
                                     "              display: \"flex\",\n" +
                                     "              transform: \"translate(50%,-50%)\",\n" +
                                     "              borderRadius: \"50%\"\n" +
                                     "            }}\n" +
                                     "            onClick={this.toggleShrink}\n" +
                                     "          >\n" +
                                     "            <svg\n" +
                                     "              viewBox=\"0 0 24 24\"\n" +
                                     "              ref=\"toggle\"\n" +
                                     "              style={{\n" +
                                     "                position: \"absolute\",\n" +
                                     "                width: \"30px\",\n" +
                                     "                height: \"30px\",\n" +
                                     "                transform: \"translate(-20px,-8px) rotateY(180deg)\"\n" +
                                     "              }}\n" +
                                     "            >\n" +
                                     "              <path d=\"M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z\"></path>\n" +
                                     "            </svg>\n" +
                                     "          </el-button>" : ""}
          <el-carousel arrow="never" autoplay={false} trigger="click">
            {this.renderMap.map((item) => {
              let Component = item.component
              return (<el-carousel-item key={item.type}>
                <div type={item.type}>
                  <Component vueProps={this.vueProps} />
                </div>
              </el-carousel-item>)
            })}
          </el-carousel>
        </div>                           
        ${hasDesignConfiguration ? "<div\n" +
                                   "          id=\"configuration\"\n" +
                                   "          ref=\"side\"\n" +
                                   "          style={{display: \"none\", position: \"absolute\", top: 0, right: 0, zIndex: 2001}}\n" +
                                   "        >\n" +
                                   "          <DesignConfiguration vueProps={this.vueProps} />\n" +
                                   "        </div>" : ""}
      </div>                         
    )
  }
}
</script>  

<style lang="less" scoped>
#development {
  height: 100%;

  #main {
    width: 100%;
    display: inline-block;
    height: 100%;

    .el-carousel {
      height: 100%;

      ::v-deep .el-carousel__indicators {
        bottom: 120px;
        transform: scale(1.3);
        transform: translateX(-50%);

        .el-carousel__indicator .el-carousel__button {
          background: gray;
        }

        .is-active .el-carousel__button {
          background: red;
        }
      }

      ::v-deep .el-carousel__container {
        height: 100%;

        .el-carousel__item {
          & > div {
            height: 100%;
            position: relative;

            &:before {
              content: attr(type);
              position: absolute;
              bottom: 50px;
              left: 50%;
              transform: translate(-50%, -50%);
              font-size: 40px;
              color: rgba(0, 0, 0, 0.2);
            }
          }
        }
      }
    }
  }

  ${hasDesignConfiguration
    ? "#configuration {\n\n    ::v-deep .el-tabs__nav-scroll {\n      display: flex;\n      justify-content: center;\n    }\n\n    padding: 20px 10px 0 10px;\n    height: 100%;\n    background-color: #f0f2f5;\n    overflow: auto;\n    box-sizing: border-box;\n    width: 300px;\n    float: right;\n  }"
    : ""}

}
</style>
`
  // console.log(templateContent);
  fs.writeFileSync(path.resolve(__dirname, `./${basePath}/src/components/development/App.vue`), templateContent)
}

function deleteExtraFiles(basePath, viewAnswer) {
  if (!viewAnswer.some((item) => item.viewType === "designConfiguration")) {
    fse.removeSync(path.resolve(__dirname, `./${basePath}/src/components/designConfiguration`))
  }
  if (viewAnswer.some(item => item.viewType == "main" && item.process == false)) {
    fse.removeSync(path.resolve(__dirname, `./${basePath}/src/components/main/eventActionDesinitions.js`))
  }
}

function generateNewFiles(basePath, viewAnswer) {
  const hasDesignConfiguration = viewAnswer.some((item) => {
    return item.viewType == "designConfiguration"
  })
  viewAnswer.forEach((item) => {
    let templateContent = ""
    if (item.viewType != "designConfiguration") {
      let componentName = `${item.viewType.slice(0, 1).toUpperCase()}${item.viewType.slice(1)}`
      templateContent = `<template>
  <div>
    ${hasDesignConfiguration ? "{{ number }}" : ""}${item.process ? "\n    <button @click=\"handleClick\">逻辑控制事件触发样例</button>" : ""}
  </div>
</template>

<script>
${item.process ? "import platformMixin from \"@/mixins/platform.js\"\n" : ""}
export default {
  name: "Main",
  props: {
    vueProps: Object
  },${item.process ? "\n  mixins: [platformMixin]," : ""}
  computed: {},
  data() {
    return {
      ${hasDesignConfiguration ? "number: 1" : ""}
    }
  },
  mounted() {
    this.vueProps.eventBus?.on((newProps) => {

    })${item.process ? "\n    this.vueProps.triggerEvent?.(\"mounted\")" : ""}
    this.initComData()
  },
  methods: {
    initComData() {${hasDesignConfiguration ? "\n      const {customConfig} = this.vueProps\n      customConfig.number && (this.number = customConfig.number)" : ""}
    },${item.process ? "\n    handleClick() {\n" +
                       "      this.vueProps.triggerEvent?.(\"click\", {value: \"123\"})\n" +
                       "    },\n" +
                       "    //action样例\n" +
                       "    do_EventCenter_message({value}) {\n" +
                       "      alert(value)\n" +
                       "    }" : ""} 
  }
}
</script>
`
    } else {
      templateContent = `<template>
  <div>
    <!--    id为组件唯一标识，用于识别逻辑控制，不可删除-->
    <div>id:</div>
    <el-input v-model="id"></el-input>
    <!--  按钮为样例，正式开发请删除-->
    <el-button @click="handleClick">配置项与主渲染区域交互样例</el-button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      id: this.vueProps.customConfig.id,
      customConfig: this.vueProps.customConfig
    }
  },
  mounted() {},
  watch: {
    "id"(val) {
      this.customConfig.id = val
      this.vueProps.changeCustomConfig(JSON.stringify(this.customConfig))
    }
  },
  props: {
    vueProps: Object
  },
  methods: {
    handleClick() {
      this.customConfig.number = this.customConfig.number || 1
      this.customConfig.number++
      //JSON.stringify在解析proxy对象时会丢失数据，请确保customConfig属性中没有proxy对象
      this.vueProps.changeCustomConfig(JSON.stringify(this.customConfig))
    },
  }
}
</script>
`
    }
    mkdirSync(path.resolve(__dirname, `./${basePath}/src/components/${item.viewType}`))
    if (item.process) {
      fse.copySync(path.resolve(__dirname, `./vue/src/components/main/eventActionDefinitions.js`), path.resolve(__dirname, `./${basePath}/src/components/${item.viewType}/eventActionDefinitions.js`))
    }
    fs.writeFileSync(path.resolve(__dirname, `./${basePath}/src/components/${item.viewType}/App.vue`), templateContent)
    // console.log(templateContent);
  })

}

function handleComponentsIndexjs(basePath, viewAnswer) {
  let importStatement = viewAnswer.map((item) => {
    return `import ${item.viewType.slice(0, 1).toUpperCase()}${item.viewType.slice(1)} from "./${item.viewType}/App.vue";`
  }).join("\n")
  let exportStatement = viewAnswer.map((item) => {
    return `${item.viewType.slice(0, 1).toUpperCase()}${item.viewType.slice(1)}`
  }).join(",\n  ")
  let componentsIndexjs = `${importStatement}
import Development from "./development/App.vue";
import OnlineDevelopmentModeDetails from "./development/OnlineDevelopmentModeDetails.vue"
export {
  Development, 
  OnlineDevelopmentModeDetails,
  ${exportStatement}
};

`
  // console.log(componentsIndexjs)
  fs.writeFileSync(path.resolve(__dirname, `./${basePath}/src/components/index.js`), componentsIndexjs)
}

function handleAppVue(basePath, viewAnswer) {
  let importStatement = viewAnswer.map((item) => {
    return `${item.viewType.slice(0, 1).toUpperCase()}${item.viewType.slice(1)}`
  }).join(",\n  ")
  let renderMap = viewAnswer.map((item) => {
    return `${item.viewType}: ${item.viewType.slice(0, 1).toUpperCase()}${item.viewType.slice(1)}`
  }).join(",\n      ")
  let srcAppVue = `<script>
import {
  ${importStatement}
} from "./components"
import adapter from "./utils/handlePlatform/adapter.js";

export default {
  name: "App",
  components: { 
    ${importStatement} 
  },
  props: {
    vueProps: Object
  },
  newProps: null,
  computed: {},
  watch: {},
  created() {
  },
  mounted() {
    this.vueProps.eventBus.on((newProps) => {
      this.newProps = adapter(newProps)
    })
  },
  beforeDestroy() {
  },
  methods: {},
  render(h) {
    const renderhMap = {
      ${renderMap}
    }
    const Comp = renderhMap[this.vueProps.type]
    return <Comp vueProps={this.newProps ? this.newProps : this.vueProps} />
  }
}
</script>
`
  fs.writeFileSync(path.resolve(__dirname, `./${basePath}/src/App.vue`), srcAppVue)
}

function mkdirSync(dirname) {
  if (fs.existsSync(dirname)) {
    return true
  } else {
    //如果父级目录已经创建，然后才能创建子级目录
    if (mkdirSync(path.dirname(dirname))) {
      fs.mkdirSync(dirname)
      return true
    }
  }
}
